package com.esl.coordinator.client.connector;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.esl.coordinator.util.Hex;

public class STiTEQSocketConnector implements SocketConnector {
	static final Logger LOG = LoggerFactory
			.getLogger(STiTEQSocketConnector.class);

	public static int SOCKET_TIMEOUT = 3000;

	private Socket sock;
	private InputStream sockInput;
	private OutputStream sockOutput;

	public static STiTEQSocketConnector getInstance() {
		return new STiTEQSocketConnector();
	}

	private STiTEQSocketConnector() {
		// empty constructor
	}

	public boolean openSocket(String targetCoordinatorAddress,
			int targetCoordinatorPort) throws UnknownHostException, IOException {
		LOG.debug("Opening connection to " + targetCoordinatorAddress
				+ " port " + targetCoordinatorPort);

		sock = new Socket(targetCoordinatorAddress, targetCoordinatorPort);
		sock.setSoTimeout(SOCKET_TIMEOUT);
		sockInput = sock.getInputStream();
		sockOutput = sock.getOutputStream();

		return true;
	}

	public synchronized String sendMessasge(byte[] command,
			int expectedResponseBytes) throws IOException {
		LOG.debug("About to start reading/writing to/from socket.");

		byte[] bytesRead = new byte[expectedResponseBytes];
		try {
			sockOutput.write(command, 0, command.length);
			sockInput.read(bytesRead, 0, expectedResponseBytes); // only read
			// expected
			// bytes
			// (blocking)
		} catch (SocketTimeoutException e) {
			LOG.error("Socket connection timed out. Current timeout set to: "
					+ SOCKET_TIMEOUT + "ms", e);
		}

		LOG.debug("STiTEQSocketConnector: Sent " + command.length
				+ " bytes to server. Message sent: " + Hex.toHexString(command));

		LOG.debug("STiTEQSocketConnector: Received msg = "
				+ Hex.toHexString(bytesRead));

		LOG.debug("Done reading/writing to/from socket, closing socket.");

		return Hex.toHexString(bytesRead);
	}

	public void closeSocket() {
		try {
			sockInput.close();
			sockOutput.close();
			sock.close();
		} catch (IOException e) {
			LOG.error("Error closing Socket Connection.", e);
		}
		LOG.debug("Exiting.");
	}

	@Override
	protected void finalize() throws Throwable {
		try {
			sock.close();
		} catch (IOException e) {
			LOG.error("Error closing Socket Connection.", e);
		}
		super.finalize();
	}

	@Override
	public boolean isOpen() {
		return sock.isConnected();
	}

}
